package com.alpaca.recommend.mapreduce;

import com.alpaca.recommend.dto.Constants;
import com.alpaca.recommend.dto.UserItemDTO;
import com.alpaca.recommend.hbase.HTableClients;
import com.alpaca.recommend.util.MD5Util;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by wangj on 2015/2/10.
 */
public class CalculateDefaultRecommend {

    public static final byte[] ITEM_FAMILY = "i".getBytes();
    public static final byte[] ITEM_CHANNELCODE_QU = "cc".getBytes();


    public static final byte[] RANK_BYTES = "r".getBytes();
    public static final byte[] ITEM_IDS_BYTES = Bytes.toBytes("ids");

    static class  CalDefaultUserItemRankMapper extends TableMapper<Text,Text> {
        protected void map(ImmutableBytesWritable key, Result value, Context context) throws IOException, InterruptedException {
            try{
                Cell itemCell = value.getColumnLatestCell(ITEM_FAMILY , ITEM_CHANNELCODE_QU);
                if(itemCell!=null){
                    String channelCode = Bytes.toString(CellUtil.cloneValue(itemCell));
                    long createTime = itemCell.getTimestamp();
                    String itemId = Bytes.toString(value.getRow());
                    context.write(new Text(channelCode) ,new Text(itemId+"_"+createTime));
                }
            }catch (Exception e){
                System.out.println(e);
            }
        }
    }

    static class  CalDefaultUserItemRankReduce extends TableReducer<Text,Text , ImmutableBytesWritable> {
        @Override
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            String rowKey = MD5Util.md5(0)+MD5Util.md5(key.toString());
            System.out.println("rowkey:"+rowKey);
            List<UserItemDTO> itemList = new ArrayList<UserItemDTO>();
            for (Text itemTime : values){
                String itemTimeStr = new String(itemTime.getBytes());
                String[] parts = itemTimeStr.split("_");
                String itemId = parts[0];
                long time = Long.valueOf(parts[1]);
                itemList.add(new UserItemDTO(itemId,time));
            }
            Collections.sort(itemList , new Comparator<UserItemDTO>() {
                @Override
                public int compare(UserItemDTO o1, UserItemDTO o2) {
                    return (int)(o2.getCreateTime() - o1.getCreateTime());
                }
            });
            int count = 0;
            StringBuilder sb = new StringBuilder();
            for (UserItemDTO rank : itemList) {
                if(count >= Constants.RECOMMEND_NUM_LIMIT)break;
                sb.append(rank.getItemId()).append(",");
                count++;
            }
            String ids = sb.substring(0 , sb.length() - 1);

            Put put = new Put(Bytes.toBytes(rowKey));
            put.add(RANK_BYTES, ITEM_IDS_BYTES, Bytes.toBytes(ids));

            context.write(null, put);
        }
    }

    public static boolean executeJob() throws IOException, ClassNotFoundException, InterruptedException {
        System.out.println("1111111");
        Configuration conf = new HTableClients().getConf();
        String table = "items";
        String reduceTable = "u_recommends";

        Job job = Job.getInstance(conf,"Calculate to u_items rank");
        job.setJarByClass(CalculateDefaultRecommend.class);

        Scan scan = new Scan();
        scan.setCaching(500);        // 1 is the default in Scan, which will be bad for MapReduce jobs
        scan.setCacheBlocks(false);  // don't set to true for MR jobs
        scan.setMaxVersions(1);
        TableMapReduceUtil.initTableMapperJob(
                table,
                scan,
                CalDefaultUserItemRankMapper.class,
                Text.class,
                Text.class,
                job);

        TableMapReduceUtil.initTableReducerJob(
                reduceTable,        // output table
                CalDefaultUserItemRankReduce.class,    // reducer class
                job);
        job.setNumReduceTasks(1);
        boolean b = job.waitForCompletion(true);
        return b;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        CalculateDefaultRecommend recommend = new CalculateDefaultRecommend();
        recommend.executeJob();
    }
}
